home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
10,000 Great Games
/
10,000 Great Games.iso
/
Product
/
66
/
data1.cab
/
Source_Files
/
Src
/
Surface.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2000-01-16
|
8KB
|
373 lines
#include "stdafx.h"
cSurface::cSurface(int _x, int _y, int _w, int _h, int _total_h, int _edge, int _transparent, int _usescreen, int _dirty_block)
{
// Dimensions
screen_x = _x;
screen_y = _y;
w = _w;
h = _h;
// Parameters
total_h = _total_h;
edge = _edge;
transparent = _transparent;
usescreen = _usescreen && !no_blit_hardware && hardware_blit_caps;
// Dirty
dirty_block = _dirty_block;
dirty_w = w / dirty_block;
dirty_h = h / dirty_block;
dirty = new char [dirty_w * dirty_h];
ASSERT(w % dirty_block == 0 && h % dirty_block == 0);
// Reset start and dirty
reset();
// Make surface
if (!usescreen)
{
// A separate buffer is used which must be blit into the backbuffer
offset_x = 0, offset_y = 0;
dds = create_surface(w, h, no_blit_hardware || !hardware_blit_caps? DDSCAPS_SYSTEMMEMORY:0, transparent? DDSD_CKSRCBLT:0);
if (dds == 0)
error("Unable to create game surface");
scroll_src_dds = dds;
}
else
{
// The backbuffer of the screen is directly used,
// which is faster but not possible for parallax scrolling
offset_x = screen_x, offset_y = screen_y;
dds = backbuffer;
scroll_src_dds = inawin? backbuffer:screen;
}
// Get caps
if (FAILED(dds->GetCaps(&caps)))
error("Unable to get capabilities for surface");
}
cSurface::~cSurface()
{
if (!usescreen)
dds->Release();
safe_delete(&dirty);
}
void cSurface::clear_backbuffer(int color)
{
// Setup effect for blit
DDBLTFX ddbltfx;
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwFillColor = color;
// Do clear
CRect r(screen_x, screen_y, screen_x + w, screen_y + h);
while (!draw_ok(backbuffer->Blt(&r, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx)));
}
void cSurface::blit_to_backbuffer()
{
if (!usescreen)
{
// Setup rectangle for blit
CRect r(0, 0, w, h);
// Do blit
while (!draw_ok(backbuffer->BltFast(screen_x, screen_y, dds, &r, DDBLTFAST_WAIT | (transparent? DDBLTFAST_SRCCOLORKEY:DDBLTFAST_NOCOLORKEY))));
}
}
int cSurface::convert_area(int &x1, int &y1, int &x2, int &y2)
{
// Convert to surface coordinates
y1 = start + h - 1 - y1;
y2 = start + h - 1 - y2;
// Clip
limit_lowerbound(x1, 0);
limit_upperbound(x2, w - 1);
limit_lowerbound(y1, 0);
limit_upperbound(y2, h - 1);
// Check if anything is on screen
if (x1 > x2 || y1 > y2)
return FALSE;
// Compute results
x1 /= dirty_block;
y1 /= dirty_block;
x2 /= dirty_block;
y2 /= dirty_block;
// Return computation succeeded
return TRUE;
}
void cSurface::reset()
{
// Reset start
last_start = 0;
start = 0;
// Reset dirty
reset_dirty();
}
void cSurface::reset_dirty()
{
// Make everything not dirty
FillMemory(dirty, dirty_w * dirty_h, FALSE);
}
void cSurface::all_dirty()
{
// Make everything dirty
FillMemory(dirty, dirty_w * dirty_h, TRUE);
}
void cSurface::add_dirty(int x1, int y1, int x2, int y2)
{
// Get area to set
if (!convert_area(x1, y1, x2, y2))
return;
// Set area dirty
char *d = dirty + x1 + y1 * dirty_w;
for (; y1 <= y2; y1++, d += dirty_w)
FillMemory(d, x2 - x1 + 1, TRUE);
}
void cSurface::all_surfaces_dirty()
{
game_surface->all_dirty();
if (!no_parallax)
back_surface->all_dirty();
left_surface->all_dirty();
right_surface->all_dirty();
}
void cSurface::all_surfaces_not_dirty()
{
game_surface->reset_dirty();
if (!no_parallax)
back_surface->reset_dirty();
left_surface->reset_dirty();
right_surface->reset_dirty();
}
void cSurface::do_scroll()
{
// Get scroll difference
int delta = start - last_start;
// Remember new start
last_start = start;
// Scroll difference up or down
if (delta > 0)
{
// Scroll up
if (delta < h)
{
// Scroll
CRect r(offset_x, offset_y, offset_x + w, offset_y + h - delta);
while (!draw_ok(dds->BltFast(offset_x, offset_y + delta, scroll_src_dds, &r, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT)));
// Make area dirty
add_dirty(0, start + h - 1, w - 1, start + h - delta);
}
else
{
// Everything is dirty
all_dirty();
}
}
else if (delta < 0)
{
// Scroll down
if (delta > -h)
{
// Scroll
CRect r(offset_x, offset_y - delta, offset_x + w, offset_y + h);
while (!draw_ok(dds->BltFast(offset_x, offset_y, scroll_src_dds, &r, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT)));
// Make area dirty
add_dirty(0, start - delta, w - 1, start);
}
else
{
// Everything is dirty
all_dirty();
}
}
else if (scroll_src_dds != dds)
{
// Copy screen to backbuffer
CRect r(offset_x, offset_y, offset_x + w, offset_y + h);
while (!draw_ok(dds->BltFast(offset_x, offset_y, scroll_src_dds, &r, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT)));
}
}
void cSurface::clear(int color)
{
// Setup effect for blit
DDBLTFX ddbltfx;
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwFillColor = color;
// Clear
CRect r(0, 0, w, h);
while (!draw_ok(dds->Blt(&r, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx)));
}
void cSurface::clear_dirty(int color)
{
// Set blit effects structure
DDBLTFX ddbltfx;
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwFillColor = color;
// Check dirty areas and clear them
char *d = dirty;
for (int y = 0; y < h; y += dirty_block)
for (int x = 0; x < w; x += dirty_block, d++)
if (*d)
{
CRect r(x, y, x + dirty_block, y + dirty_block);
while (!draw_ok(dds->Blt(&r, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx)));
}
}
void cSurface::write_tiled(cBMP *bmp)
{
// tilestart is the start of the tile
int tilestart = start + h - ((start + h) / bmp->h + 1) * bmp->h;
// Get best pointer to dd surface
LPDIRECTDRAWSURFACE4 best = bmp->bestptr(this);
// Check dirty areas and clear them
char *d = dirty;
for (int y = 0; y < h; y += dirty_block)
for (int x = 0; x < w; x += dirty_block, d++)
if (*d)
{
// Get source range in image
int y1 = (y - tilestart) % bmp->h,
y2 = (y - tilestart + dirty_block - 1) % bmp->h;
// Write the background
CRect r(x, y1, x + dirty_block, y2 > y1? y2 + 1: bmp->h);
while (!draw_ok(dds->BltFast(offset_x + x, offset_y + y, best, &r, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT)));
// Check if there's a second part and write it
if (y1 > y2)
{
CRect r(x, 0, x + dirty_block, y2 + 1);
while (!draw_ok(dds->BltFast(offset_x + x, offset_y + y + bmp->h - y1, best, &r, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT)));
}
}
}
void cSurface::write_displayable(cDisplayable *l)
{
for (; l != 0; l = (cDisplayable *)l->next)
{
// Get area occupied by this displayable
int x1 = l->x1, y1 = l->y1, x2 = l->x2, y2 = l->y2;
if (!convert_area(x1, y1, x2, y2))
continue;
// Write dirty blocks, writing as much as possible in horizontal direction
for (; y1 <= y2; y1++)
{
char *d = dirty + x1 + y1 * dirty_w;
int y_game = start + h - 1 - y1 * dirty_block;
for (int x = x1; x <= x2; x++, d++)
if (*d)
{
// Remember first block to write
int x_start = x * dirty_block;
// Get last block to write
for (x++, d++; x <= x2 && *d; x++, d++);
// Write horizontal line of blocks
l->write(x_start, y_game, x * dirty_block - 1, y_game - dirty_block + 1);
}
}
}
}